package com.xqboss.apps.service.equipment;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.xqboss.apps.domain.equipment.*;
import com.xqboss.apps.domain.nft.Nft;
import com.xqboss.apps.dto.PageDto;
import com.xqboss.apps.dto.equipment.*;
import com.xqboss.apps.enums.market.MarketTypeEnum;
import com.xqboss.apps.service.nft.NftService;
import com.xqboss.apps.vo.equipment.EquipmentSmeltTemplateDetailVo;
import com.xqboss.apps.vo.equipment.EquipmentSmeltTemplateNftVo;
import com.xqboss.apps.vo.equipment.EquipmentSmeltTemplateVo;
import com.xqboss.common.core.domain.PageList;
import com.xqboss.common.exception.ServiceException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.xqboss.apps.mapper.equipment.EquipmentSmeltTemplateMapper;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;


/**
 * 装备-熔炼模版(EquipmentSmeltTemplate)表服务实现类
 *
 * @author makejava
 * @since 2024-03-01 11:44:14
 */
@Service
public class EquipmentSmeltTemplateService extends ServiceImpl<EquipmentSmeltTemplateMapper, EquipmentSmeltTemplate> {

    @Autowired
    private EquipmentSmeltTemplateNftService templateNftService;

    @Autowired
    private EquipmentSmeltTemplateProduceBasicService templateProduceBasicService;

    @Autowired
    private EquipmentSmeltTemplateProduceWorstService templateProduceWorstService;

    @Autowired
    private EquipmentSmeltTemplateProduceLuckyService templateProduceLuckyService;

    @Lazy
    @Autowired
    private NftService nftService;

    /**
     * 分页列表
     * @param param
     * @return
     */
    public PageList<EquipmentSmeltTemplateVo> pageList(PageDto param) {
        PageList<EquipmentSmeltTemplateVo> pageList = new PageList<>();
        Page<EquipmentSmeltTemplate> page = new Page<>(param.getPageNum(), param.getPageSize());
        page = this.lambdaQuery()
                .like(StrUtil.isNotBlank(param.getKeywords()), EquipmentSmeltTemplate::getName, param.getKeywords())
                .orderByDesc(EquipmentSmeltTemplate::getId)
                .page(page);
        pageList.setList(BeanUtil.copyToList(page.getRecords(), EquipmentSmeltTemplateVo.class));
        pageList.setTotal(page.getTotal());
        for (EquipmentSmeltTemplateVo t : pageList.getList()) {
            List<EquipmentSmeltTemplateNft> templateNftList = templateNftService.lambdaQuery()
                    .eq(EquipmentSmeltTemplateNft::getTemplateId, t.getId())
                    .list();
            if (!templateNftList.isEmpty()) {
                t.setNftIdList(templateNftList.stream().map(EquipmentSmeltTemplateNft::getNftId).collect(Collectors.toList()));
                t.setNftCount(templateNftList.size());
            } else {
                t.setNftIdList(new ArrayList<>());
                t.setNftCount(0);
            }
        }
        return pageList;
    }

    /**
     * 获取熔炼模版详情
     * @param id
     * @return
     */
    public EquipmentSmeltTemplateDetailVo detail(Long id) {
        EquipmentSmeltTemplateDetailVo detail = new EquipmentSmeltTemplateDetailVo();
        EquipmentSmeltTemplate template = this.getById(id);
        BeanUtil.copyProperties(template, detail);
        detail.setBasicList(templateProduceBasicService.lambdaQuery()
                .eq(EquipmentSmeltTemplateProduceBasic::getTemplateId, id)
                .list()
        );
        detail.setWorstList(templateProduceWorstService.lambdaQuery()
                .eq(EquipmentSmeltTemplateProduceWorst::getTemplateId, id)
                .list()
        );
        detail.setLuckyList(templateProduceLuckyService.lambdaQuery()
                .eq(EquipmentSmeltTemplateProduceLucky::getTemplateId, id)
                .list()
        );
        return detail;
    }

    /**
     * 新增
     * @param params
     */
    @Transactional
    public void add(EquipmentSmeltTemplateSaveDto params) {
        EquipmentSmeltTemplate template = new EquipmentSmeltTemplate();
        BeanUtil.copyProperties(params, template);
        validateSave(params);
        this.save(template);
        List<EquipmentSmeltTemplateProduceBasic> basicList = BeanUtil.copyToList(params.getBasicList(), EquipmentSmeltTemplateProduceBasic.class);
        List<EquipmentSmeltTemplateProduceWorst> worstList = BeanUtil.copyToList(params.getWorstList(), EquipmentSmeltTemplateProduceWorst.class);
        List<EquipmentSmeltTemplateProduceLucky> luckyList = new ArrayList<>();
        if (params.getLuckyList() != null) {
            luckyList = BeanUtil.copyToList(params.getLuckyList(), EquipmentSmeltTemplateProduceLucky.class);
        }
        basicList.forEach(t -> t.setTemplateId(template.getId()));
        worstList.forEach(t -> t.setTemplateId(template.getId()));
        luckyList.forEach(t -> t.setTemplateId(template.getId()));
        templateProduceBasicService.saveBatch(basicList);
        templateProduceWorstService.saveBatch(worstList);
        if (!luckyList.isEmpty()) {
            templateProduceLuckyService.saveBatch(luckyList);
        }
    }

    /**
     * 修改
     * @param params
     */
    @Transactional
    public void edit(EquipmentSmeltTemplateSaveDto params) {
        if (params.getId() == null) {
            throw new ServiceException("请输入模板ID");
        }
        EquipmentSmeltTemplate template = this.getById(params.getId());
        if (template == null) {
            throw new ServiceException("模板不存在");
        }
        validateSave(params);
        BeanUtil.copyProperties(params, template);

        this.updateById(template);
        // 修改产出配置
        List<EquipmentSmeltTemplateProduceBasic> basicList = BeanUtil.copyToList(params.getBasicList(), EquipmentSmeltTemplateProduceBasic.class);
        List<EquipmentSmeltTemplateProduceWorst> worstList = BeanUtil.copyToList(params.getWorstList(), EquipmentSmeltTemplateProduceWorst.class);
        List<EquipmentSmeltTemplateProduceLucky> luckyList = new ArrayList<>();
        if (params.getLuckyList() != null) {
            luckyList = BeanUtil.copyToList(params.getLuckyList(), EquipmentSmeltTemplateProduceLucky.class);
        }
        // 判断是否有新增或删除
        List<Long> basicIdList = basicList.stream().map(EquipmentSmeltTemplateProduceBasic::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> worstIdList = worstList.stream().map(EquipmentSmeltTemplateProduceWorst::getId).filter(Objects::nonNull).collect(Collectors.toList());
        List<Long> luckyIdList = luckyList.stream().map(EquipmentSmeltTemplateProduceLucky::getId).filter(Objects::nonNull).collect(Collectors.toList());
        LambdaUpdateWrapper<EquipmentSmeltTemplateProduceBasic> basicWrapper = new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<EquipmentSmeltTemplateProduceWorst> worstWrapper = new LambdaUpdateWrapper<>();
        LambdaUpdateWrapper<EquipmentSmeltTemplateProduceLucky> luckyWrapper = new LambdaUpdateWrapper<>();
        basicWrapper.eq(EquipmentSmeltTemplateProduceBasic::getTemplateId, template.getId());
        worstWrapper.eq(EquipmentSmeltTemplateProduceWorst::getTemplateId, template.getId());
        luckyWrapper.eq(EquipmentSmeltTemplateProduceLucky::getTemplateId, template.getId());
        if (!basicIdList.isEmpty()) {
            basicWrapper.notIn(EquipmentSmeltTemplateProduceBasic::getId, basicIdList);
        }
        if (!worstIdList.isEmpty()) {
            worstWrapper.notIn(EquipmentSmeltTemplateProduceWorst::getId, worstIdList);
        }
        if (!luckyIdList.isEmpty()) {
            luckyWrapper.notIn(EquipmentSmeltTemplateProduceLucky::getId, luckyIdList);
        }
        templateProduceBasicService.remove(basicWrapper);
        templateProduceWorstService.remove(worstWrapper);
        templateProduceLuckyService.remove(luckyWrapper);
        basicList.forEach(t -> t.setTemplateId(template.getId()));
        worstList.forEach(t -> t.setTemplateId(template.getId()));
        luckyList.forEach(t -> t.setTemplateId(template.getId()));
        templateProduceBasicService.saveOrUpdateBatch(basicList);
        templateProduceWorstService.saveOrUpdateBatch(worstList);
        if (!luckyList.isEmpty()) {
            templateProduceLuckyService.saveOrUpdateBatch(luckyList);
        }
    }

    /**
     * 删除
     * @param id
     */
    @Transactional
    public void delete(Long id) {
        this.removeById(id);
        templateNftService.lambdaUpdate()
                .eq(EquipmentSmeltTemplateNft::getTemplateId, id)
                .remove();
        templateProduceBasicService.lambdaUpdate()
                .eq(EquipmentSmeltTemplateProduceBasic::getTemplateId, id)
                .remove();
        templateProduceWorstService.lambdaUpdate()
                .eq(EquipmentSmeltTemplateProduceWorst::getTemplateId, id)
                .remove();
        templateProduceLuckyService.lambdaUpdate()
                .eq(EquipmentSmeltTemplateProduceLucky::getTemplateId, id)
                .remove();
    }

    /**
     * 关联藏品分页列表
     * @param params
     * @return
     */
    public PageList<EquipmentSmeltTemplateNftVo> nftPageList(EquipmentSmeltTemplateNftQueryDto params) {
        if (params.getTemplateId() != null) {
            params.setNftIdList(templateNftService.lambdaQuery()
                    .select(EquipmentSmeltTemplateNft::getNftId)
                    .eq(EquipmentSmeltTemplateNft::getTemplateId, params.getTemplateId())
                    .list()
                    .stream()
                    .map(EquipmentSmeltTemplateNft::getNftId)
                    .collect(Collectors.toList())
            );
        }
        params.startPage();
        List<EquipmentSmeltTemplateNftVo> list = baseMapper.selectNftList(params);
        return new PageList<>(list, ((com.github.pagehelper.Page<?>)list).getTotal());
    }

    /**
     * 关联藏品保存
     * @param params
     */
    @Transactional
    public void nftSave(EquipmentSmeltTemplateNftSaveDto params) {
        // 如果藏品在其他模板中已经存在，则删除之前的关联
        templateNftService.lambdaUpdate()
                .in(EquipmentSmeltTemplateNft::getNftId, params.getNftIdList())
                .ne(EquipmentSmeltTemplateNft::getTemplateId, params.getTemplateId())
                .remove();
        // 和数据库里的作比较，找出需要删除的和需要新增的
        List<EquipmentSmeltTemplateNft> dbList = templateNftService.lambdaQuery()
                .eq(EquipmentSmeltTemplateNft::getTemplateId, params.getTemplateId())
                .list();
        List<Long> dbNftIdList = dbList.stream().map(EquipmentSmeltTemplateNft::getNftId).collect(Collectors.toList());
        List<Long> newNftIdList = params.getNftIdList();
        List<Long> deleteList = new ArrayList<>();
        List<Long> addList = new ArrayList<>();
        for (Long nftId : dbNftIdList) {
            if (!newNftIdList.contains(nftId)) {
                deleteList.add(nftId);
            }
        }
        for (Long nftId : newNftIdList) {
            if (!dbNftIdList.contains(nftId)) {
                addList.add(nftId);
            }
        }
        if (!deleteList.isEmpty()) {
            templateNftService.lambdaUpdate()
                    .eq(EquipmentSmeltTemplateNft::getTemplateId, params.getTemplateId())
                    .in(EquipmentSmeltTemplateNft::getNftId, deleteList)
                    .remove();
        }
        if (!addList.isEmpty()) {
            List<EquipmentSmeltTemplateNft> addNftList = new ArrayList<>();
            for (Long nftId : addList) {
                EquipmentSmeltTemplateNft nft = new EquipmentSmeltTemplateNft();
                nft.setTemplateId(params.getTemplateId());
                nft.setNftId(nftId);
                addNftList.add(nft);
            }
            templateNftService.saveBatch(addNftList);
        }

    }

    /**
     * 关联藏品保存(单个)
     * @param nftId
     * @param templateId
     */
    @Transactional
    public void nftSave(Long nftId, Long templateId) {
        // 如果有则更换，没有则新增
        EquipmentSmeltTemplateNft templateNft = templateNftService.lambdaQuery()
                .eq(EquipmentSmeltTemplateNft::getNftId, nftId)
                .one();
        if (templateNft == null) {
            templateNft = new EquipmentSmeltTemplateNft();
            templateNft.setTemplateId(templateId);
            templateNft.setNftId(nftId);
            templateNftService.save(templateNft);
        } else {
            templateNftService.lambdaUpdate()
                    .set(EquipmentSmeltTemplateNft::getTemplateId, templateId)
                    .eq(EquipmentSmeltTemplateNft::getId, templateNft.getId())
                    .update();
        }
    }


    /**
     * 验证保存参数
     * @param params
     * @return
     */
    public void validateSave(EquipmentSmeltTemplateSaveDto params) {
        if(params.getBasicList().isEmpty()) {
            throw new ServiceException("基础产出不能为空");
        }
        // name是否重复
        this.lambdaQuery()
                .ne(params.getId() != null, EquipmentSmeltTemplate::getId, params.getId())
                .eq(EquipmentSmeltTemplate::getName, params.getName())
                .oneOpt()
                .ifPresent(t -> {
                    throw new ServiceException("模板名称已存在");
                });
        // 是否有库存,把数组里的藏品id拿出来，去数据库里查，看是否有库存
        Set<Long> nftIdList = new HashSet<>();
        nftIdList.addAll(params.getBasicList().stream()
                .filter(t -> t.getType() == MarketTypeEnum.NORMAL)
                .map(EquipmentSmeltTemplateProduceBasicDto::getSourceId)
                .collect(Collectors.toSet()));
        if (params.getWorstList() != null) {
            nftIdList.addAll(params.getWorstList().stream()
                    .filter(t -> t.getType() == MarketTypeEnum.NORMAL)
                    .map(EquipmentSmeltTemplateProduceWorstDto::getSourceId)
                    .collect(Collectors.toSet()));
        }
        if (params.getLuckyList() != null) {
            nftIdList.addAll(params.getLuckyList().stream()
                    .filter(t -> t.getType() == MarketTypeEnum.NORMAL)
                    .map(EquipmentSmeltTemplateProduceLuckyDto::getSourceId)
                    .collect(Collectors.toSet()));
        }
        nftService.lambdaQuery().in(Nft::getId, nftIdList).list().forEach(t -> {
            if (t.getStock() <= 0) {
                throw new ServiceException(t.getTitle() + "库存不足");
            }
        });
    }
}
